<template>
  <div class="app-container">
    <!-- 工具栏 -->
    <div class="head-container">
      <div v-if="crud.props.searchToggle">
        <!-- 搜索 -->
        <label class="el-form-item-label">资源名称</label>
        <el-input
          v-model="query.resourceName"
          clearable
          placeholder="资源名称"
          style="width: 185px;"
          class="filter-item"
          @keyup.enter.native="crud.toQuery"
        />
        <label class="el-form-item-label">资源类型</label>
        <el-select
          v-model="query.resourceType"
          clearable
          placeholder="选择资源类型"
          style="width: 185px;"
          class="filter-item"
        >
          <el-option label="API" value="0" />
<!--          <el-option label="数据库" value="1" />-->
          <el-option label="文件" value="2" />
        </el-select>
        <rrOperation :crud="crud" />
      </div>
      <!-- 工具栏按钮 -->
      <crudOperation :permission="permission" />
      <!-- 表单组件 -->
      <el-dialog
        :close-on-click-modal="false"
        :before-close="crud.cancelCU"
        :visible.sync="crud.status.cu > 0"
        :title="crud.status.title"
        width="1000px"
      >
        <!-- 修复：将 dynamicRules 改为 rules -->
        <el-form ref="form" :model="crud.form" :rules="rules" size="small" label-width="110px" class="custom-form">
          <div class="form-grid">
            <el-form-item label="资源名称" prop="resourceName">
              <el-input
                v-model="crud.form.resourceName"
                style="width: 100%;"
                :disabled="crud.form.resourceType == 0"
                placeholder="请输入资源名称"
              >
                <template #suffix>
                  <el-button
                    v-if="crud.form.resourceType == 0"
                    icon="el-icon-search"
                    size="mini"
                    type="text"
                    style="padding: 0 5px;"
                    @click="openResourceForm"
                  />
                </template>
              </el-input>
            </el-form-item>
            <el-form-item label="资源说明" prop="resourceSm">
              <el-input v-model="crud.form.resourceSm" style="width: 100%;" placeholder="请输入资源说明" />
            </el-form-item>
            <el-form-item label="数据项说明">
              <el-input
                v-model="crud.form.resourceDataItem"
                style="width: 100%;"
                placeholder="请输入数据项说明"
                :rows="1"
                type="textarea"
              />
            </el-form-item>
            <el-form-item v-if="crud.form.resourceType == 0" label="请求方式" prop="resourceApiMethod">
              <el-select v-model="crud.form.resourceApiMethod" style="width: 100%;" placeholder="请选择请求方式">
                <el-option label="POST" value="0" />
                <el-option label="GET" value="1" />
              </el-select>
            </el-form-item>
          </div>

          <!-- 资源类型单选按钮组 -->
          <div class="resource-type-selection">
            <el-form-item label="资源类型" prop="resourceType" class="resource-type-item">
              <el-radio-group v-model="crud.form.resourceType" @change="handleResourceTypeChange">
                <el-radio-button label="0">API</el-radio-button>
<!--                <el-radio-button label="1">数据库</el-radio-button>-->
                <el-radio-button label="1">文件</el-radio-button>
              </el-radio-group>
            </el-form-item>
          </div>

          <!-- 根据选择的资源类型显示对应内容 -->
          <div v-if="crud.form.resourceType !== null" class="resource-content">
            <!-- API内容 -->
            <div v-if="crud.form.resourceType === '0'" class="api-content">
              <el-form-item label="API资源URL" prop="resourceApiUrl">
                <el-input v-model="crud.form.resourceApiUrl" placeholder="请输入API资源URL" />
              </el-form-item>

              <!-- 入参表格 -->
              <div class="table-section">
                <div class="table-header">
                  <h4>入参配置 (API资源请求)</h4>
                </div>
                <div class="json-input-section">
                  <!-- 1. JSON 输入文本框（支持粘贴） -->
                  <!-- <el-input v-model="rawJson" type="textarea"
                    placeholder="粘贴入参JSON格式代码（示例：[{&quot;fieldName&quot;:&quot;userName&quot;,&quot;fieldComment&quot;:&quot;用户名&quot;,&quot;fieldDescription&quot;:&quot;用户登录名称&quot;}]）"
                    rows="6" class="json-input" @input="handleJsonInput" />

                  <div v-if="jsonError" class="error-tip">{{ jsonError }}</div>

                  <div v-if="validJson" class="json-preview">
                    <h4>格式化预览</h4>
                    <vue-json-pretty :data="validJson" :deep="3" :show-length="true" :show-line-number="true"
                      theme="light" />
                  </div>

                  <div class="json-tools">
                    <el-button size="mini" type="primary" :disabled="!rawJson" @click="formatJson">
                      格式化 JSON
                    </el-button>
                    <el-button size="mini" type="text" @click="clearJson">
                      清空
                    </el-button>
                  </div> -->
                  <codemirror v-model="rawJson" :style="codemirrorStyle" :options="cmOptions" @ready="onCmReady" />
                </div>
              </div>
              <!-- 出参表格 -->
              <!-- 出参表格（替换原有注释代码） -->
              <div class="table-section">
                <div class="table-header">
                  <h4>出参配置 (API资源返回)1</h4>
                </div>

                <!-- 出参JSON输入区域（与入参结构完全一致） -->
                <div class="json-input-section">

                  <!-- <el-input v-model="rawJsonRsp" type="textarea"
                    placeholder="粘贴出参JSON格式代码（示例：[{&quot;fieldName&quot;:&quot;userName&quot;,&quot;fieldComment&quot;:&quot;用户名&quot;,&quot;fieldDescription&quot;:&quot;用户登录名称&quot;}]）"
                    rows="6" class="json-input" @input="handleJsonInputRsp" />

                  <div v-if="jsonErrorRsp" class="error-tip">{{ jsonErrorRsp }}</div>

                  <div v-if="validJsonRsp" class="json-preview">
                    <h4>格式化预览</h4>
                    <vue-json-pretty :data="validJsonRsp" :deep="3" :show-length="true" :show-line-number="true"
                      theme="light" />
                  </div>

                  <div class="json-tools">
                    <el-button size="mini" type="primary" :disabled="!rawJsonRsp" @click="formatJsonRsp">
                      格式化 JSON
                    </el-button>
                    <el-button size="mini" type="text" @click="clearJsonRsp">
                      清空
                    </el-button>
                  </div> -->

                  <codemirror v-model="rawJsonRsp" :style="codemirrorStyle" :options="cmOptions" @ready="onCmReady" />
                </div>
              </div>
            </div>
            <!-- 数据库内容 -->
<!--            <div v-if="crud.form.resourceType === '1'" class="database-content">-->
<!--              <el-row :gutter="20">-->
<!--                <el-col :span="12">-->
<!--                  <el-form-item label="数据库IP" prop="resourceDataIp">-->
<!--                    <el-input-->
<!--                      v-model="crud.form.resourceDataIp"-->
<!--                      maxlength="15"-->
<!--                      placeholder="请输入数据库IP"-->
<!--                      @input="handleIpInput"-->
<!--                      @blur="validateIp"-->
<!--                    />-->
<!--                  </el-form-item>-->
<!--                </el-col>-->
<!--                <el-col :span="12">-->
<!--                  <el-form-item label="数据库端口" prop="resourceDataPort">-->
<!--                    <el-input-->
<!--                      v-model="crud.form.resourceDataPort"-->
<!--                      maxlength="5"-->
<!--                      placeholder="请输入数据库端口"-->
<!--                      @input="handlePortInput"-->
<!--                      @blur="validatePort"-->
<!--                    />-->
<!--                  </el-form-item>-->
<!--                </el-col>-->
<!--              </el-row>-->

<!--              <el-row :gutter="20">-->
<!--                <el-col :span="12">-->
<!--                  <el-form-item label="数据库类型" prop="resourceDataType">-->
<!--                    <el-select v-model="crud.form.resourceDataType" placeholder="请选择数据库类型">-->
<!--                      <el-option label="MySQL" value="mysql" />-->
<!--                      <el-option label="Oracle" value="oracle" />-->
<!--                      <el-option label="PostgreSQL" value="postgresql" />-->
<!--                      <el-option label="SQL Server" value="sqlserver" />-->
<!--                      <el-option label="MongoDB" value="mongodb" />-->
<!--                    </el-select>-->
<!--                  </el-form-item>-->
<!--                </el-col>-->
<!--                <el-col :span="12">-->
<!--                  <el-form-item label="数据库实例" prop="resourceDataName">-->
<!--                    <el-input v-model="crud.form.resourceDataName" placeholder="请输入数据库实例名" />-->
<!--                  </el-form-item>-->
<!--                </el-col>-->
<!--              </el-row>-->

<!--              <el-row :gutter="20">-->
<!--                <el-col :span="12">-->
<!--                  <el-form-item label="数据库账号" prop="resourceDataAccount">-->
<!--                    <el-input v-model="crud.form.resourceDataAccount" placeholder="请输入数据库账号" />-->
<!--                  </el-form-item>-->
<!--                </el-col>-->
<!--                <el-col :span="12">-->
<!--                  <el-form-item label="数据库密码" prop="resourceDataPassword">-->
<!--                    <el-input v-model="crud.form.resourceDataPassword" type="password" placeholder="请输入数据库密码" />-->
<!--                  </el-form-item>-->
<!--                </el-col>-->
<!--              </el-row>-->
<!--            </div>-->
            <!-- 文件内容 -->
            <div v-if="crud.form.resourceType === '1'" class="file-content">
              <el-form-item label="文件上传" prop="fileUpload">
                <div class="file-upload-container">
                  <el-upload
                    class="upload-demo"
                    :action="`${baseApi}/api/dataResource/fileAdd`"
                    :file-list="fileList"
                    :limit="1"
                    :on-exceed="handleExceed"
                    :before-remove="beforeRemove"
                    :headers="headers"
                    :on-remove="handleRemove"
                    :on-error="handleUploadError"
                    :on-success="handleUploadSuccess"
                    :show-file-list="true"
                    @click="handleFileListClick"
                  >
                    <el-button size="small" type="primary">点击上传</el-button>
                  </el-upload>
                </div>
              </el-form-item>
              <el-form-item v-if="crud.status.add === 1" label="文件路径" prop="resourceFilePath">
                <el-input v-model="crud.form.resourceFilePath" style="width: 100%;" placeholder="请输入文件路径" />
              </el-form-item>
            </div>
          </div>
        </el-form>
        <div slot="footer" class="dialog-footer">
          <el-button type="text" @click="crud.cancelCU">取消</el-button>
          <el-button :loading="crud.status.cu === 2" type="primary" @click="submitForm">确认</el-button>
        </div>
      </el-dialog>
      <!-- 表格渲染 -->
      <el-table
        ref="table"
        v-loading="crud.loading"
        :data="crud.data"
        size="small"
        style="width: 100%;"
        @selection-change="crud.selectionChangeHandler"
      >
        <el-table-column type="selection" width="55" />
        <el-table-column prop="resourceName" label="资源名称" />
        <el-table-column prop="resourceType" label="资源类型">
          <template slot-scope="scope">
            <el-tag
              :type="scope.row.resourceType === '0' ? 'primary' : scope.row.resourceType === '1' ? 'success' : 'warning'"
            >
              {{ scope.row.resourceType === '0' ? 'API' : scope.row.resourceType === '1' ? '文件' : '' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="resourceSm" label="资源说明" />
        <el-table-column prop="resourceDataItem" label="数据项说明" />
        <el-table-column prop="createTime" label="创建时间" />
        <el-table-column prop="updateTime" label="更新时间" />
        <el-table-column prop="createBy" label="创建人" />
        <el-table-column prop="updateBy" label="更新人" />
        <el-table-column
          v-if="checkPer(['admin', 'dataResource:edit', 'dataResource:del'])"
          label="操作"
          width="200px"
          align="center"
        >
          <template slot-scope="scope">
            <el-button type="text" size="mini" class="preview-btn" @click="showPreview(scope.row)">
              查看
            </el-button>
            <udOperation :data="scope.row" :permission="permission" :crud="crud" />
          </template>
        </el-table-column>
      </el-table>
      <!-- 分页组件 -->
      <pagination />
    </div>
    <!-- 接口选择弹窗 -->
    <el-dialog
      title="选择API接口"
      :visible.sync="resourceFormVisible"
      width="800px"
      :close-on-click-modal="false"
      class="api-select-dialog"
    >
      <div class="api-search-section">
        <el-input
          v-model="apiSearchKeyword"
          placeholder="请输入接口名称搜索"
          prefix-icon="el-icon-search"
          clearable
          style="margin-bottom: 20px;margin-right: 10px;width:660px"
          @keyup.enter.native="searchApis"
        />
        <el-button @click="searchApis">搜索</el-button>
      </div>

      <el-table
        v-loading="apiTableLoading"
        :data="apiTableData"
        border
        highlight-current-row
        height="400"
        class="api-select-table"
        @current-change="handleApiRowSelect"
      >
        <el-table-column type="index" width="50" label="序号" />
        <el-table-column prop="name" label="接口名称" min-width="200">
          <template slot-scope="scope">
            <el-tooltip :content="scope.row.description || '暂无描述'" placement="top">
              <span class="api-name">{{ scope.row.name }}</span>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>

      <div class="pagination-wrapper">
        <el-pagination
          :current-page="apiPagination.currentPage"
          :page-sizes="[5, 10, 20, 50]"
          :page-size="apiPagination.pageSize"
          :total="apiPagination.total"
          layout="total, sizes, prev, pager, next, jumper"
          :small="false"
          @size-change="handleApiPageSizeChange"
          @current-change="handleApiCurrentPageChange"
        />
      </div>

      <div slot="footer" class="dialog-footer">
        <el-button @click="resourceFormVisible = false">取消</el-button>
        <el-button type="primary" :disabled="!selectedApi" @click="confirmApiSelect">
          确定选择
        </el-button>
      </div>
    </el-dialog>

    <!-- 预览弹窗 -->
    <el-dialog
      :title="previewTitle"
      :visible.sync="previewVisible"
      width="800px"
      :close-on-click-modal="false"
      :before-close="handlePreviewClose"
      class="preview-dialog"
    >
      <div v-loading="previewLoading" class="preview-content">
        <!-- 基础信息 -->
        <div class="preview-section">
          <h3 class="preview-section-title">基础信息</h3>
          <el-descriptions :column="1" border>
            <el-descriptions-item label="资源名称">{{ previewData.resourceName }}</el-descriptions-item>
            <el-descriptions-item label="资源类型">
              {{ previewData.resourceType === '0' ? 'API' : previewData.resourceType === '1' ? '文件':'' }}
            </el-descriptions-item>
            <el-descriptions-item label="创建时间">{{ previewData.createTime }}</el-descriptions-item>
            <el-descriptions-item label="更新时间">{{ previewData.updateTime }}</el-descriptions-item>
            <el-descriptions-item label="创建人">{{ previewData.createBy }}</el-descriptions-item>
          </el-descriptions>
        </div>

        <!-- API详情 -->
        <div v-if="previewData.resourceType === '0'" class="preview-section">
          <h3 class="preview-section-title">API详情</h3>
          <el-descriptions :column="1" border>
            <el-descriptions-item label="资源说明">{{ previewData.resourceSm || '无' }}</el-descriptions-item>
            <el-descriptions-item label="数据项说明">{{ previewData.resourceDataItem || '无' }}</el-descriptions-item>
            <el-descriptions-item label="请求方式">
              {{ previewData.resourceApiMethod === '0' ? 'POST' : 'GET' }}
            </el-descriptions-item>
            <el-descriptions-item label="API资源URL">{{ previewData.resourceApiUrl || '无' }}</el-descriptions-item>
            <el-descriptions-item label="入参配置">
              <div class="preview-table-section">
                {{ previewData.resourceApiReq }}
                <!--                <div v-else class="no-data-tip">暂无入参配置</div>-->
              </div>
            </el-descriptions-item>

            <!-- 出参表格 -->
            <el-descriptions-item label="出参配置">
              <div class="preview-table-section">
                {{ previewData.resourceApiRsp }}
                <!--                <div v-else class="no-data-tip">暂无出参配置</div>-->
              </div>
            </el-descriptions-item>
          </el-descriptions>
        </div>

        <!-- 数据库详情 -->
<!--        <div v-if="previewData.resourceType === '1'" class="preview-section">-->
<!--          <h3 class="preview-section-title">数据库详情</h3>-->
<!--          <el-descriptions :column="1" border>-->
<!--            <el-descriptions-item label="资源说明">{{ previewData.resourceSm || '无' }}</el-descriptions-item>-->
<!--            <el-descriptions-item label="数据项说明">{{ previewData.resourceDataItem || '无' }}</el-descriptions-item>-->
<!--            <el-descriptions-item label="数据库IP">{{ previewData.resourceDataIp || '无' }}</el-descriptions-item>-->
<!--            <el-descriptions-item label="数据库类型">{{ previewData.resourceDataType || '无' }}</el-descriptions-item>-->
<!--            <el-descriptions-item label="数据库端口">{{ previewData.resourceDataPort || '无' }}</el-descriptions-item>-->
<!--            <el-descriptions-item label="数据库实例">{{ previewData.resourceDataName || '无' }}</el-descriptions-item>-->
<!--          </el-descriptions>-->
<!--        </div>-->

        <!-- 文件详情 -->
        <div v-if="previewData.resourceType === '1'" class="preview-section">
          <h3 class="preview-section-title">文件详情</h3>
          <el-descriptions :column="1" border>
            <el-descriptions-item label="文件路径">{{ previewData.resourceFilePath || '无' }}</el-descriptions-item>
            <el-descriptions-item label="资源说明">{{ previewData.resourceSm || '无' }}</el-descriptions-item>
            <el-descriptions-item label="数据项说明">{{ previewData.resourceDataItem || '无' }}</el-descriptions-item>
          </el-descriptions>
        </div>
      </div>

      <div slot="footer" class="dialog-footer">
        <el-button @click="previewVisible = false">关闭</el-button>
      </div>
    </el-dialog>
  </div>
</template>
<script>
import json5 from 'json5'
// import VueJsonPretty from 'vue-json-pretty'
import 'vue-json-pretty/lib/styles.css'
import axios from 'axios'
import crudDataResource from '@/api/system/dataResource'
import CRUD, { presenter, header, form, crud } from '@crud/crud'
import rrOperation from '@crud/RR.operation.vue'
import crudOperation from '@crud/CRUD.operation.vue'
import udOperation from '@crud/UD.operation.vue'
import pagination from '@crud/Pagination'
import { CXdataResource, queryXhAllAPI, downloadByRid } from '@/api/xwZx'
import { mapGetters } from 'vuex'
import { getToken } from '@/utils/auth'
import { codemirror } from 'vue-codemirror'

import 'codemirror/lib/codemirror.css'
import 'codemirror/addon/lint/lint'
import 'codemirror/addon/lint/lint.css'
import 'codemirror/addon/lint/json-lint'
import 'codemirror/addon/lint/javascript-lint'
import 'codemirror/mode/javascript/javascript.js'
import 'codemirror/theme/base16-dark.css'
import 'codemirror/addon/fold/foldgutter.css'
import 'codemirror/addon/fold/foldcode'
import 'codemirror/addon/fold/foldgutter'
import 'codemirror/addon/fold/brace-fold'
import 'codemirror/addon/fold/comment-fold'
import 'codemirror/addon/fold/markdown-fold'
import 'codemirror/addon/fold/xml-fold'
import 'codemirror/addon/fold/indent-fold'
import 'codemirror/addon/hint/show-hint.css'
import 'codemirror/addon/hint/show-hint.js'
import 'codemirror/addon/hint/javascript-hint'
import 'codemirror/addon/hint/xml-hint'
import 'codemirror/addon/hint/sql-hint'
import 'codemirror/addon/hint/anyword-hint'
import 'codemirror/addon/search/match-highlighter'
import 'codemirror/addon/edit/matchbrackets'
import 'codemirror/addon/edit/closebrackets'
import 'codemirror/mode/css/css.js'
import 'codemirror/mode/vue/vue.js'

// import { beautify } from 'js-beautify'

const defaultForm = {
  id: null,
  resourceName: null,
  resourceType: null,
  resourceSm: null,
  resourceDataItem: null,
  resourceApiReq: null,
  resourceApiRsp: null,
  resourceApiUrl: null,
  resourceApiMethod: null,
  resourceApiReqnum: null,
  resourceFilePath: null,
  resourceFileDownloadCount: null,
  resourceDataCount: null,
  resourceDataIp: null,
  resourceDataPort: null,
  resourceDataAccount: null,
  resourceDataPassword: null,
  resourceDataType: null,
  resourceDataName: null,
  createTime: null,
  updateTime: null,
  createBy: null,
  updateBy: null,
  resourceApiId: null,
  fileList: null,
  fileId: null
}
export default {
  name: 'DataResource',
  components: { crudOperation, rrOperation, udOperation, pagination, codemirror },
  mixins: [presenter(), header(), form(defaultForm), crud()],
  cruds() {
    return CRUD({
      // title: 'dataresource',
      title: '',
      url: 'api/dataResource',
      idField: 'id',
      sort: 'id,desc',
      crudMethod: { ...crudDataResource },
      query: {
        id: '',
        resourceName: '',
        resourceType: '',
        resourceApiMethod: ''
      },
      optShow: {
        add: true,
        edit: true,
        del: true,
        download: false,
        refresh: true
      }
    })
  },

  data() {
    return {
      ipError: '', // 存储IP错误信息
      portError: '', // 存储端口错误信息
      rawJson: '', // 原始输入的 JSON 文本
      validJson: null, // 解析后合法的 JSON 对象
      jsonError: '', // JSON 解析错误信息
      // 新增：出参JSON数据（专属命名，避免冲突）
      rawJsonRsp: '', // 出参原始JSON文本
      validJsonRsp: null, // 出参解析后合法JSON
      jsonErrorRsp: '', // 出参JSON错误信息
      customOptShow: {
        download: false
      },
      response: '',
      headers: { 'Authorization': getToken() },
      resourceForm: {
        type: '',
        tag: '',
        createTime: ''
      },
      resourceFormVisible: false,
      // API接口选择相关数据
      apiSearchKeyword: '',
      apiTableData: [],
      apiTableLoading: false,
      selectedApi: null,
      selectedApiUuid: '',
      apiPagination: {
        currentPage: 1,
        pageSize: 10,
        total: 0
      },
      allApiData: [],
      // API入参数据
      inputParams: [],
      // API出参数据
      outputParams: [],
      // 文件上传列表
      fileList: [],
      // 选中的文件对象
      selectedFile: null,
      // 文件预览相关
      filePreviewUrl: null,
      fileTextContent: '',
      permission: {
        add: ['admin', 'dataResource:add'],
        edit: ['admin', 'dataResource:edit'],
        del: ['admin', 'dataResource:del']
      },
      // 完善表单验证规则
      rules: {
        resourceName: [
          { required: true, message: '资源名称不能为空', trigger: 'blur' }
        ],
        resourceType: [
          { required: true, message: '请选择资源类型', trigger: 'change' }
        ],
        resourceSm: [
          { required: true, message: '资源说明不能为空', trigger: 'blur' }
        ],
        // API相关验证规则
        resourceApiUrl: [
          {
            required: true, message: 'API资源URL不能为空', trigger: 'blur',
            validator: (rule, value, callback) => {
              if (this.crud.form.resourceType === '0' && !value) {
                callback(new Error('API资源URL不能为空'))
              } else {
                callback()
              }
            }
          }
        ],
        resourceApiMethod: [
          {
            required: true, message: '请选择请求方式', trigger: 'change',
            validator: (rule, value, callback) => {
              if (this.crud.form.resourceType === '0' && (value === null || value === undefined)) {
                callback(new Error('请选择请求方式'))
              } else {
                callback()
              }
            }
          }
        ],
        // 文件相关验证规则
        resourceFilePath: [
          {
            required: true, message: '文件路径不能为空', trigger: 'blur',
            validator: (rule, value, callback) => {
              if (this.crud.form.resourceType === '1' && !value) {
                callback(new Error('文件路径不能为空'))
              } else {
                callback()
              }
            }
          }
        ],
        // 数据库相关验证规则
        resourceDataIp: [
          { required: true, message: '数据库IP不能为空', trigger: 'blur' },
          {
            trigger: ['blur', 'change'],
            validator: (rule, value, callback) => {
              const ip = (value || '').trim()
              if (!ip) {
                callback(new Error('数据库IP不能为空'))
                return
              }
              // IPv4正则优化：允许中间段为空（输入过程中），但最终校验严格
              // 完整IP规则：4段数字，每段0-255，禁止前导零（除非是0本身）
              const ipReg = /^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/
              if (!ipReg.test(ip)) {
                callback(new Error('请输入有效的IPv4地址（如192.168.1.1）'))
              } else {
                callback()
              }
            }
          }
        ],
        resourceDataPort: [
          { required: true, message: '数据库端口不能为空', trigger: 'blur' },
          // 新增：端口格式自定义校验
          {
            trigger: ['blur', 'change'],
            validator: (rule, value, callback) => {
              const portStr = (value || '').trim()
              if (!portStr) {
                callback(new Error('数据库端口不能为空'))
                return
              }
              const port = Number(portStr)
              // 端口范围：1-65535，且必须是整数
              if (isNaN(port) || !Number.isInteger(port) || port < 1 || port > 65535) {
                callback(new Error('请输入有效的端口号（1-65535）'))
              } else {
                callback() // 校验通过
              }
            }
          }
        ],
        // resourceDataType: [
        //   {
        //     required: true, message: '请选择数据库类型', trigger: 'change',
        //     validator: (rule, value, callback) => {
        //       if (this.crud.form.resourceType === '1' && !value) {
        //         callback(new Error('请选择数据库类型'))
        //       } else {
        //         callback()
        //       }
        //     }
        //   }
        // ],
        // resourceDataName: [
        //   {
        //     required: true, message: '数据库实例不能为空', trigger: 'blur',
        //     validator: (rule, value, callback) => {
        //       if (this.crud.form.resourceType === '1' && !value) {
        //         callback(new Error('数据库实例不能为空'))
        //       } else {
        //         callback()
        //       }
        //     }
        //   }
        // ],
        // resourceDataAccount: [
        //   {
        //     required: true, message: '数据库账号不能为空', trigger: 'blur',
        //     validator: (rule, value, callback) => {
        //       if (this.crud.form.resourceType === '1' && !value) {
        //         callback(new Error('数据库账号不能为空'))
        //       } else {
        //         callback()
        //       }
        //     }
        //   }
        // ],
        // resourceDataPassword: [
        //   {
        //     required: true, message: '数据库密码不能为空', trigger: 'blur',
        //     validator: (rule, value, callback) => {
        //       if (this.crud.form.resourceType === '1' && !value) {
        //         callback(new Error('数据库密码不能为空'))
        //       } else {
        //         callback()
        //       }
        //     }
        //   }
        // ]
      },
      queryTypeOptions: [
        { key: 'id', display_name: '主键' },
        { key: 'resourceName', display_name: '资源名称' },
        { key: 'resourceType', display_name: '资源类型：0-API，2-数据库，1-文件' },
        { key: 'resourceApiMethod', display_name: '请求方式：0-POST,1-GET' }
      ],
      // 预览功能相关
      previewVisible: false,
      previewTitle: '资源预览',
      previewData: {},
      previewLoading: false,
      previewInputParams: [],

      code: '',
      cmOptions: {
        // mode: 'text/javascript',
        mode: 'application/json',

        gutters: ['CodeMirror-lint-markers', 'CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
        lineNumbers: true,
        line: true,
        lint: true,
        lineWrapping: true,
        autofocus: true,
        autoCloseBrackets: true,
        foldGutter: true, // 块槽
        hintOptions: { completeSingle: true },
        matchTags: { bothTags: true },
        matchBrackets: true,
        showCursorWhenSelecting: true,
        styleSelectedText: true,
        styleActiveLine: true,
        autoRefresh: true,
        highlightSelectionMatches: {
          minChars: 2,
          trim: true,
          style: 'matchhighlight',
          showToken: false
        }
      },
      codemirrorStyle: {
        fontSize: '18px',
        lineHeight: '150%',
        height: '300px',
        border: '1px solid #EBEEF5'
      }

    }
  },

  computed: {
    ...mapGetters(['baseApi']),
    isImageFile() {
      if (!this.selectedFile) return false
      const imageTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/bmp', 'image/webp']
      return imageTypes.includes(this.selectedFile.type)
    },
    isTextFile() {
      if (!this.selectedFile) return false
      const textTypes = ['text/plain', 'text/csv', 'application/json', 'text/xml', 'application/xml']
      return textTypes.includes(this.selectedFile.type) || this.selectedFile.name.endsWith('.txt') ||
        this.selectedFile.name.endsWith('.csv') || this.selectedFile.name.endsWith('.json') ||
        this.selectedFile.name.endsWith('.xml')
    }
  },

  watch: {
    // 监听表单数据变化，用于恢复入参出参数据
    'crud.form': {
      handler(newForm, oldForm) {
        // 当表单数据发生变化且是API类型时，尝试恢复入参出参数据
        if (newForm && newForm.resourceType === '0') {
          if (newForm.resourceApiReq) {
            try {
              const parsedInput = newForm.resourceApiReq
              this.rawJson = parsedInput // 同步到输入框
              this.validJson = parsedInput // 同步到格式化预览
            } catch (e) {
              console.error('Watch恢复入参失败:', e)
            }
          }

          // -------------------------- 新增：同步出参输入框 --------------------------
          if (newForm.resourceApiRsp) {
            try {
              const parsedOutput = newForm.resourceApiRsp
              this.rawJsonRsp = parsedOutput// 同步到输入框
              this.validJsonRsp = parsedOutput // 同步到格式化预览
            } catch (e) {
              console.error('Watch恢复出参失败:', e)
            }
          }

          // 检查是否需要恢复入参数据
          if (newForm.resourceApiReq && this.inputParams.length === 0) {
            try {
              const parsedInput = newForm.resourceApiReq
              if (Array.isArray(parsedInput) && parsedInput.length > 0) {
                this.inputParams = [...parsedInput]
                console.log('从表单恢复入参数据:', this.inputParams)
              }
            } catch (e) {
              console.error('恢复入参数据失败:', e)
            }
          }

          // 检查是否需要恢复出参数据
          if (newForm.resourceApiRsp && this.outputParams.length === 0) {
            try {
              const parsedOutput = newForm.resourceApiRsp
              if (Array.isArray(parsedOutput) && parsedOutput.length > 0) {
                this.outputParams = [...parsedOutput]
                console.log('从表单恢复出参数据:', this.outputParams)
              }
            } catch (e) {
              console.error('恢复出参数据失败:', e)
            }
          }
        }
      },
      deep: true,
      immediate: true
    }
  },
  mounted() {
    console.log('上传URL:', `${this.baseApi}/api/dataResource`)
    console.log('当前组件的crud对象：', this.crud)
  },
  methods: {
    // 封装重置JSON数据的方法
    resetJsonData() {
      this.rawJson = ''
      this.rawJsonRsp = ''
      this.validJson = { input: null, output: null }
      this.jsonError = { input: '', output: '' }
      this.validJsonRsp = { input: null, output: null }
      this.jsonErrorRsp = { input: '', output: '' }
      // 可以在这里同时重置表单中关联的字段
      this.crud.form.resourceApiReq = null
      this.crud.form.resourceApiRsp = null
    },
    handleJsonInput() {
      if (!this.rawJson) {
        this.validJson = null
        this.jsonError = ''
        return
      }
      try {
        // 尝试解析 JSON，校验格式
        const parsed = json5.parse(this.rawJson)
        this.validJson = parsed
        this.jsonError = ''
      } catch (err) {
        this.validJson = null
        this.jsonError = `JSON 格式错误：${err.message}`
      }
    },
    // 格式化 JSON（带缩进，更易读）
    formatJson() {
      try {
        const parsed = json5.parse(this.rawJson)
        // 用 2 个空格缩进格式化
        this.rawJson = json5.stringify(parsed, null, 2)
        this.validJson = parsed
      } catch (err) {
        this.$message.error('请先输入合法的 JSON 格式')
      }
    },
    // 清空输入
    clearJson() {
      this.rawJson = ''
      this.validJson = null
      this.jsonError = ''
    },
    // 新增：出参JSON输入校验（与入参逻辑一致）
    handleJsonInputRsp() {
      if (!this.rawJsonRsp) {
        this.validJsonRsp = null
        this.jsonErrorRsp = ''
        return
      }
      try {
        const parsed = json5.parse(this.rawJsonRsp)
        this.validJsonRsp = parsed
        this.jsonErrorRsp = ''
        // 实时同步到后端出参字段（可选，确保数据实时更新）
        this.crud.form.resourceApiRsp = this.rawJsonRsp
      } catch (err) {
        this.validJsonRsp = null
        this.jsonErrorRsp = `JSON 格式错误：${err.message}`
      }
    },
    // 新增：出参JSON格式化
    formatJsonRsp() {
      try {
        const parsed = json5.parse(this.rawJsonRsp)
        this.rawJsonRsp = json5.stringify(parsed, null, 2)
        this.validJsonRsp = parsed
        // 格式化后同步到后端出参字段
        this.crud.form.resourceApiRsp = this.rawJsonRsp
      } catch (err) {
        this.$message.error('请先输入合法的 JSON 格式')
      }
    },
    // 新增：出参JSON清空
    clearJsonRsp() {
      this.rawJsonRsp = ''
      this.validJsonRsp = null
      this.jsonErrorRsp = ''
      // 清空后同步到后端出参字段
      this.crud.form.resourceApiRsp = ''
    },
    // 事件代理：监听父容器点击，判断是否点击了文件列表项
    handleFileListClick(e) {
      // Element 2.x 默认文件列表项的类名为 "el-upload-list__item"
      const fileItem = e.target.closest('.el-upload-list__item-name')
      if (!fileItem) return // 未点击文件项，直接返回

      // 通过文件项的 "data-uid" 属性获取文件的 uid（Element 内置属性）
      const fileUid = fileItem.getAttribute('data-uid')
      // 从文件列表中匹配对应的文件
      const targetFile = this.fileList.find(file => file.uid === fileUid)
      if (targetFile) {
        console.log('点击默认文件项', targetFile)
        // 示例：预览图片
      }
    },
    // 上传成功（静态提示）
    handleUploadSuccess(response, file, fileList) {
      // 验证后端返回数据（需包含file的核心信息：id、name、fileSize等）
      if (response && response.name) {
        // 更新文件列表：将后端返回的id、文件名等信息合并到文件对象中
        const updatedFile = {
          ...file,
          id: response.id, // 后端返回的文件唯一标识（用于删除/预览）
          name: response.name, // 后端存储的文件名（避免前端文件名异常）
          size: response.fileSize, // 后端返回的文件大小（如"1.75MB"）
          url: `${this.baseApi}/api/dataFile/download/${response.id}` // 预览/下载地址
        }
        this.fileList = [updatedFile] // 单文件场景，直接替换列表

        // 提示上传成功（显示文件名和大小）
        this.$message.success(`文件 "${response.name}"（${response.fileSize}）上传成功`)

        // 关键：将文件ID绑定到表单（供后续提交表单时使用）
        this.crud.form.fileId = response.id
        this.crud.form.resourceFilePath = response.location
        this.crud.form.resourceName = response.name
        this.crud.form.resourceFileType = response.extensionName
      } else {
        this.$message.error('文件上传成功，但返回数据格式异常，请检查')
        console.error('上传成功但数据异常：', response)
        this.fileList = fileList // 异常时仍更新列表（避免显示异常）
      }
    },
    handleUploadError(err, file, fileList) {
      // 错误提示（区分接口错误、网络错误、后端校验错误）
      const errMsg = err.response?.data?.msg || err.message || '上传失败，请重试'
      this.$message.error(`文件 "${file.name}" 上传失败：${errMsg}`)
      console.error('文件上传错误：', err)
    },
    handleRemove(file, fileList) {
      // 调用删除接口，添加headers
      axios.post(
        `${this.baseApi}/api/dataFile/deleteDataFile/${file.id}`,
        {}, // 这里是请求体，删除接口如果不需要可以传空对象
        {
          headers: this.headers
        }
      )
        .then(() => {
          this.$message.success(`文件 "${file.name}" 已删除`)
          // 从表单数据中移除该文件ID
          this.fileList = []
          this.crud.form.fileId = null
          this.crud.form.resourceFilePath = null
          this.crud.form.resourceName = null
        })
    },
    handlePreview(file) {
      console.log(file)
    },
    handleExceed(files, fileList) {
      this.$message.warning(`最多只能上传1个文件，当前已选择 ${fileList.length + files.length} 个文件`)
    },
    beforeRemove(file, fileList) {
      return this.$confirm(`确定要删除文件 "${file.name}" 吗？`)
    },
    // 钩子：在获取表格数据之前执行
    [CRUD.HOOK.beforeRefresh]() {
      return true
    },
    // 钩子：在获取数据成功后执行
    [CRUD.HOOK.afterRefresh]() {
      // 页面刷新后尝试恢复当前编辑中的数据
      this.tryRestoreParamsData()
    },

    // 尝试恢复入参出参数据的方法
    tryRestoreParamsData() {
      // 仅当资源类型是API（'0'）且表单有数据时才处理
      if (this.crud?.form && this.crud.form.resourceType === '0') {
        // -------------------------- 入参数据恢复 --------------------------
        if (this.crud.form.resourceApiReq) {
          try {
            // 1. 解析后端返回的入参JSON，赋值给表格数据（inputParams）
            const parsedInput = json5.parse(this.crud.form.resourceApiReq)
            if (Array.isArray(parsedInput)) {
              this.inputParams = [...parsedInput]
            }
            // 2. 同步到输入框绑定变量（rawJson），确保输入框显示
            this.rawJson = json5.stringify(parsedInput, null, 2)
            // 3. 同步到格式化预览变量（validJson）
            this.validJson = parsedInput
            console.log('刷新后恢复入参数据:', this.inputParams, this.rawJson)
          } catch (e) {
            console.error('刷新后恢复入参数据失败:', e)
            // 解析失败时清空，避免页面报错
            this.inputParams = []
            this.rawJson = ''
            this.validJson = null
          }
        } else {
          // 后端无入参数据时清空
          this.inputParams = []
          this.rawJson = ''
          this.validJson = null
        }

        // -------------------------- 出参数据恢复 --------------------------
        if (this.crud.form.resourceApiRsp) {
          try {
            // 1. 解析后端返回的出参JSON，赋值给表格数据（outputParams）
            const parsedOutput = json5.parse(this.crud.form.resourceApiRsp)
            if (Array.isArray(parsedOutput)) {
              this.outputParams = [...parsedOutput]
            }
            // 2. 同步到输入框绑定变量（rawJsonRsp），确保输入框显示
            this.rawJsonRsp = json5.stringify(parsedOutput, null, 2)
            // 3. 同步到格式化预览变量（validJsonRsp）
            this.validJsonRsp = parsedOutput
            console.log('刷新后恢复出参数据:', this.outputParams, this.rawJsonRsp)
          } catch (e) {
            console.error('刷新后恢复出参数据失败:', e)
            // 解析失败时清空
            this.outputParams = []
            this.rawJsonRsp = ''
            this.validJsonRsp = null
          }
        } else {
          // 后端无出参数据时清空
          this.outputParams = []
          this.rawJsonRsp = ''
          this.validJsonRsp = null
        }
      }
    },

    // 钩子：在弹出编辑/新增表单前执行
    [CRUD.HOOK.beforeToCU](crud, form) {
      console.log('=== beforeToCU 钩子执行 ===',)
      setTimeout(() => {
        console.log('=== 11111 ===', crud.status, form)
      })
      this.addEventFileClick()
      if (crud.status.edit && form.resourceType === '0') {
        console.log('编辑')
        // 原有入参数据回显（保留不变）
        if (form.resourceApiReq) {
          try {
            this.inputParams = json5.parse(form.resourceApiReq)
            this.rawJson = json5.stringify(this.inputParams, null, 2) // 入参JSON文本回显
            this.validJson = this.inputParams
          } catch (e) {
            console.error('解析入参失败:', e)
            this.inputParams = []
            this.rawJson = ''
          }
        } else {
          this.inputParams = []
          this.rawJson = ''
        }

        // 新增：出参数据回显（与入参结构一致）
        if (form.resourceApiRsp) {
          try {
            this.outputParams = json5.parse(form.resourceApiRsp)
            this.rawJsonRsp = json5.stringify(this.outputParams, null, 2) // 出参JSON文本回显
            this.validJsonRsp = this.outputParams
          } catch (e) {
            console.error('解析出参失败:', e)
            this.outputParams = []
            this.rawJsonRsp = ''
          }
        } else {
          this.outputParams = []
          this.rawJsonRsp = ''
        }
      } else if (crud.status.add) {
        console.log('新增')

        // 新增操作：清空入参+出参数据（原有入参清空保留，新增出参清空）
        this.inputParams = []
        this.rawJson = ''
        this.validJson = null
        this.jsonError = ''
        this.resetJsonData()
        this.outputParams = []
        this.rawJsonRsp = ''
        this.validJsonRsp = null
        this.jsonErrorRsp = ''
      }
    },
    handleClick(tab, event) {
      console.log(tab, event)
    },
    // 新增/编辑数据资源后刷新列表
    [CRUD.HOOK.afterSubmit]() {
      this.crud.toQuery()
    },

    // 表单提交方法
    submitForm() {
      this.$refs.form.validate(valid => {
        if (valid) {
          // 执行额外的业务验证
          if (this.beforeSubmit()) {
            this.crud.submitCU()
          }
        } else {
          this.$message.error('表单验证失败，请检查填写内容')
          return false
        }
      })
    },

    // 提交前验证和调试
    beforeSubmit() {
      console.log('=== 表单提交前验证 ===')
      console.log('表单提交数据:', this.crud.form)
      console.log('apiUuid值:', this.crud.form.resourceApiId)

      const resourceType = this.crud.form.resourceType

      if (!resourceType) {
        this.$message.error('请选择资源类型!')
        return false
      }

      // API类型验证
      if (resourceType === '0') {
        // 原有入参验证（保留不变）
        if (!this.rawJson) {
          this.$message.error('请输入入参JSON配置!')
          return false
        }
        if (this.jsonError) {
          this.$message.error(`入参${this.jsonError}`)
          // return false
        }
        // 新增：出参JSON验证
        if (!this.rawJsonRsp) {
          this.$message.error('请输入出参JSON配置!')
          return false
        }
        if (this.jsonErrorRsp) {
          this.$message.error(`出参${this.jsonErrorRsp}`)
          // return false
        }
        if (!this.crud.form.resourceApiUrl) {
          this.$message.error('API资源URL不能为空!')
          return false
        }

        if (!this.crud.form.resourceApiId) {
          this.$message.error('请使用放大镜按钮选择API接口!')
          return false
        }

        this.crud.form.resourceApiReq = this.rawJson + ''
        this.crud.form.resourceApiRsp = this.rawJsonRsp + ''
        // this.crud.form.resourceApiReq = JSON.stringify(this.validJson)
        // this.crud.form.resourceApiRsp = JSON.stringify(this.validJsonRsp)
      }

      // 文件类型验证 记得解开
      // if (resourceType === '1') {
      //   if (!this.fileList || this.fileList.length === 0) {
      //     this.$message.error('请上传文件!')
      //     return false
      //   }
      // }

      // 数据库类型验证
      // if (resourceType === '1') {
      //   if (!this.crud.form.resourceDataIp) {
      //     this.$message.error('数据库IP不能为空!')
      //     return false
      //   }
      //   if (!this.crud.form.resourceDataPort) {
      //     this.$message.error('数据库端口不能为空!')
      //     return false
      //   }
      //   if (!this.crud.form.resourceDataType) {
      //     this.$message.error('请选择数据库类型!')
      //     return false
      //   }
      //   if (!this.crud.form.resourceDataName) {
      //     this.$message.error('数据库实例不能为空!')
      //     return false
      //   }
      //   if (!this.crud.form.resourceDataAccount) {
      //     this.$message.error('数据库账号不能为空!')
      //     return false
      //   }
      //   if (!this.crud.form.resourceDataPassword) {
      //     this.$message.error('数据库密码不能为空!')
      //     return false
      //   }
      // }

      console.log('=== 最终提交数据 ===')
      console.log('完整表单数据:', JSON.stringify(this.crud.form, null, 2))
      return true
    },
    // 删除数据资源后刷新列表
    [CRUD.HOOK.afterDelete]() {
      this.crud.toQuery()
    },
    // 确认选择资源
    confirmResource() {
      this.$refs.resourceForm.validate((valid) => {
        if (valid) {
          console.log('选中的资源信息:', this.resourceForm)
          if (this.resourceForm.tag) {
            this.crud.form.resourceName = this.resourceForm.tag
          }
          this.resourceFormVisible = false
        }
      })
    },
    // 打开接口选择弹窗
    openResourceForm() {
      console.log('=== 打开接口选择弹窗 ===')
      console.log('当前资源类型:', this.crud.form.resourceType)

      this.apiSearchKeyword = ''
      this.selectedApi = null
      this.selectedApiUuid = ''
      this.apiPagination.currentPage = 1
      this.apiTableData = []

      this.resourceFormVisible = true
      this.loadApiData()
    },
    // 加载API数据
    async loadApiData() {
      this.apiTableLoading = true
      try {
        // 获取所有数据，进行前端分页和搜索
        const response = await queryXhAllAPI({
          resourceName: this.apiSearchKeyword,
          page: this.apiPagination.currentPage,
          size: this.apiPagination.pageSize // 获取所有数据
        })
        // console.log('API数据响应222222222222222222222222222:', response)

        if (response && response.data) {
          this.apiTableData = response.data
        } else if (response && Array.isArray(response)) {
          this.apiTableData = response
        } else {
          this.apiTableData = response || []
        }

        this.apiPagination.total = response.pagination.total

        // console.log('加载的API数据总数1111111111111111111111111111:', this.allApiData)
        // this.updateApiTableData()
        // this.$message.success(`接口数据加载成功，共${this.allApiData.length}条`)
      } catch (error) {
        console.error('加载API数据失败:', error)
        this.$message.error('加载接口数据失败')
        this.apiTableData = []
        this.apiPagination.total = 0

        // this.updateApiTableData()
      } finally {
        this.apiTableLoading = false
      }
    },
    // 更新表格数据
    updateApiTableData() {
      let filteredData = [...this.allApiData]

      console.log('原始数据长度:', this.allApiData.length)

      // 如果有搜索关键词，进行过滤
      if (this.apiSearchKeyword && this.apiSearchKeyword.trim()) {
        filteredData = this.allApiData.filter(item =>
          (item.name && item.name.toLowerCase().includes(this.apiSearchKeyword.toLowerCase())) ||
          (item.path && item.path.toLowerCase().includes(this.apiSearchKeyword.toLowerCase()))
        )
        console.log('搜索后数据长度:', filteredData.length)
      }

      // 设置总数据量
      this.apiPagination.total = filteredData.length

      // 计算分页
      const start = (this.apiPagination.currentPage - 1) * this.apiPagination.pageSize
      const end = start + this.apiPagination.pageSize
      this.apiTableData = filteredData.slice(start, end)

      console.log('=== 分页详细信息 ===')
      console.log('当前页码:', this.apiPagination.currentPage)
      console.log('每页大小:', this.apiPagination.pageSize)
      console.log('总数据量:', this.apiPagination.total)
      console.log('过滤后数据长度:', filteredData.length)
      console.log('表格显示数据长度:', this.apiTableData.length)
      console.log('分页范围:', `${start} - ${end}`)
      console.log('当前页实际显示数据:', this.apiTableData.map(item => item.name))
    },
    // 搜索接口
    searchApis() {
      this.apiPagination.currentPage = 1
      this.loadApiData()
      // return
      // this.apiPagination.currentPage = 1
      // this.updateApiTableData()
    },
    // 选择表格行
    handleApiRowSelect(currentRow) {
      this.selectedApi = currentRow
      if (currentRow) {
        this.selectedApiUuid = currentRow.uuid
      }
    },
    // 分页大小改变
    handleApiPageSizeChange(newSize) {
      console.log('=== 分页大小改变 ===')
      console.log('新的分页大小:', newSize)
      this.apiPagination.pageSize = newSize
      // 只更新表格数据，不重新加载API数据
      this.loadApiData()
      // this.updateApiTableData()
    },

    // 当前页改变
    handleApiCurrentPageChange(newPage) {
      console.log('=== 页码改变 ===')
      console.log('新的页码:', newPage)
      this.apiPagination.currentPage = newPage
      // 只更新表格数据，不重新加载API数据
      // this.updateApiTableData()
      this.loadApiData()
    },
    // 确认选择接口
    confirmApiSelect() {
      if (!this.selectedApi) {
        this.$message.warning('请选择一个接口')
        return
      }

      console.log('=== 确认选择接口 ===')
      console.log('选中的API:', this.selectedApi)
      console.log('选中的UUID:', this.selectedApiUuid)

      this.crud.form.resourceName = this.selectedApi.name
      this.crud.form.resourceApiId = this.selectedApiUuid

      console.log('设置后的crud.form.apiUuid:111111111111111111：', this.crud.form.resourceApiId)
      console.log('当前完整表单数据:', this.crud.form)

      if (this.crud.form.resourceType === '0') {
        this.crud.form.resourceApiMethod = this.selectedApi.method === 'GET' ? '1' : '0'
      }

      this.$message.success(`已选择接口: ${this.selectedApi.name}`)
      this.resourceFormVisible = false

      this.selectedApi = null
      this.selectedApiUuid = ''
    },

    // 资源类型改变时的处理
    handleResourceTypeChange(value) {
      this.resetJsonData()
      this.inputParams = []
      this.outputParams = []
      this.fileList = []
      this.crud.form.resourceApiId = null
      this.crud.form.resourceApiUrl = null
      this.crud.form.resourceApiMethod = null
      this.crud.form.resourceName = ''
      this.crud.form.resourceApiId = ''

      console.log('资源类型改变，已清空apiUuid:', this.crud.form.resourceApiId)

      if (value === '0') {
        this.addInputParam()
        this.addOutputParam()
      }

      this.addEventFileClick()

      // 触发表单重新验证
      this.$nextTick(() => {
        this.$refs.form.clearValidate()
      })
    },
    addEventFileClick() {
      this.fileList = []
      this.$nextTick(() => {
        if (this.crud.status.edit && this.crud.form.resourceType === '2') {
          const updatedFile = {
            // ...file,
            // id: response.id, // 后端返回的文件唯一标识（用于删除/预览）
            // name: response.name, // 后端存储的文件名（避免前端文件名异常）
            // size: response.fileSize, // 后端返回的文件大小（如"1.75MB"）
            // url: `${this.baseApi}/api/dataFile/download/${response.id}` // 预览/下载地址
            id: new Date().getTime(),
            name: this.crud.form.resourceName
          }
          this.fileList = [updatedFile] // 单文件场景，直接替换列表
          this.$nextTick(() => {
            const fileDom = document.getElementsByClassName('el-upload-list__item-name')[0]
            fileDom.addEventListener('click', (e) => {
              console.log('e', e, this.crud.form)
              const id = this.crud.form.id
              if (id) {
                downloadByRid(id).then(res => {
                  console.log(res)
                  const fileName = this.crud.form.resourceName || new Date().getTime()
                  // 3. 将 blob 转换为可下载的链接
                  const blob = new Blob([res], {
                    // 根据文件类型设置 MIME 类型
                    // 常见类型：application/pdf、image/jpeg、application/vnd.ms-excel 等
                    type: 'application/octet-stream'
                  })

                  // 4. 创建 a 标签并触发下载
                  const url = window.URL.createObjectURL(blob)
                  const a = document.createElement('a')
                  a.href = url
                  a.download = fileName + `.${this.crud.form.resourceFileType}` // 设置下载文件名
                  document.body.appendChild(a)
                  a.click() // 触发点击下载

                  // 5. 清理资源
                  document.body.removeChild(a)
                  window.URL.revokeObjectURL(url) // 释放 blob URL

                  this.$message.success('文件下载成功')
                })
              }
            })
          })
        }
      })
    },

    // 添加入参
    addInputParam() {
      this.inputParams.push({
        fieldName: '',
        fieldComment: '',
        fieldDescription: ''
      })
    },

    // 删除入参
    removeInputParam(index) {
      this.inputParams.splice(index, 1)
    },

    // 添加出参
    addOutputParam() {
      this.outputParams.push({
        fieldName: '',
        fieldComment: '',
        fieldDescription: ''
      })
    },

    // 删除出参
    removeOutputParam(index) {
      this.outputParams.splice(index, 1)
    },

    // 预览功能 - 显示预览弹窗
    showPreview(row) {
      // 确保每次预览都使用新的ID
      this.previewId = row.id
      this.previewVisible = true
      this.previewTitle = `资源预览: ${row.resourceName}`
      this.previewLoading = true

      // 强制重置预览数据，解决只能查看一个的问题
      this.previewData = {}

      // 立即执行查询
      this.getResourceDetailByCX(this.previewId)
    },

    // 预览功能 - 获取资源详情
    async getResourceDetailByCX(id) {
      try {
        const response = await CXdataResource(id)
        console.log(response, 'response')
        this.previewData = response
        // const matchedItem = response.content.find(item => item.id === id)
        // if (matchedItem) {
        //   this.previewData = { ...matchedItem }
        //   // 解析入参
        //   if (this.previewData.resourceApiReq) {
        //     try {
        //       this.previewInputParams = json5.parse(this.previewData.resourceApiReq)
        //       console.log('入参解析成功：', this.previewInputParams)
        //     } catch (e) {
        //       console.error('解析入参JSON失败:', e)
        //       this.previewInputParams = []
        //       this.$message.warning('入参数据格式异常，无法展示')
        //     }
        //   }
        //   // 解析出参
        //   if (this.previewData.resourceApiRsp) {
        //     try {
        //       this.previewOutputParams = json5.parse(this.previewData.resourceApiRsp)
        //       console.log('出参解析成功：', this.previewOutputParams)
        //     } catch (e) {
        //       console.error('解析出参JSON失败:', e)
        //       this.previewOutputParams = []
        //       this.$message.warning('出参数据格式异常，无法展示')
        //     }
        //   }
        // } else {
        //   this.$message.warning('未找到该资源的详细信息')
        // }
      } catch (error) {
        console.error('获取资源详情失败:', error)
        this.$message.error('获取资源详情失败，请重试')
      } finally {
        this.previewLoading = false
      }
    },
    // 关闭预览弹窗时彻底清理数据
    handlePreviewClose() {
      this.previewVisible = false
      // 延迟清理，确保弹窗关闭后再重置数据
      setTimeout(() => {
        this.previewData = {}
        this.previewId = null
      }, 300)
    },

    handleIpInput() {
      let value = this.crud.form.resourceDataIp || ''

      // 1. 只保留数字和点，过滤所有非法字符
      value = value.replace(/[^\d.]/g, '')

      // 2. 限制点的数量（最多3个），并禁止连续点（如“192..168.1.1”）
      value = value.replace(/\.{2,}/g, '.') // 连续点替换为单个点

      // 3. 处理每段数字（0-255，禁止前导零，允许单独的0）
      const segments = value.split('.')
      const validSegments = segments.map(seg => {
        // 每段最多3位数字
        if (seg.length > 3) seg = seg.substring(0, 3)
        // 禁止前导零（仅当长度>1时）
        if (seg.length > 1 && seg.startsWith('0')) {
          seg = seg.replace(/^0+/, '') // 去掉前导零，如"012"→"12"
        }
        return seg // 保留空分段（用户可能正在输入下一段）
      }).slice(0, 4) // 最多4个分段

      // 4. 重新拼接（保留点，即使最后一段为空）
      value = validSegments.join('.')

      // 更新输入值
      this.crud.form.resourceDataIp = value
    },

    /**
     * 失去焦点时完整校验IP格式
     */
    validateIp() {
      this.$refs.form.validateField('resourceDataIp')
    },
    handlePortInput() {
      let value = this.crud.form.resourceDataPort || ''

      // 1. 只保留数字，过滤非数字字符
      value = value.replace(/[^\d]/g, '')

      // 2. 限制长度（最多5位，对应端口最大值65535）
      if (value.length > 5) value = value.substring(0, 5)

      // 3. 禁止前导零（如“03306”→“3306”，但允许“0”，后续失焦校验会排除0）
      if (value.length > 1 && value.startsWith('0')) value = value.replace(/^0+/, '')

      this.crud.form.resourceDataPort = value
    },

    /**
     * 失去焦点时验证端口有效性（1-65535）
     */
    validatePort() {
      this.$refs.form.validateField('resourceDataPort')
    },

    onCmReady(cm) {
      cm.on('inputRead', (cm, obj) => {
        if (obj.text && obj.text.length > 0) {
          const c = obj.text[0].charAt(obj.text[0].length - 1)
          if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
            cm.showHint({ completeSingle: false }) // 自动填充关闭了它
          }
        }
      })
    },
    formartJSON() {
      const code = this.code
      this.code = ''
      setTimeout(() => {
        this.code = code
      }, 5000)
    }
  }
}
</script>

<style scoped>
.json-input-section {
  background: #fff;
  padding: 16px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  margin-bottom: 20px;
}

.json-input {
  margin-bottom: 8px;
  border-color: #e4e7ed;
}

.error-tip {
  color: #f56c6c;
  font-size: 12px;
  margin-bottom: 12px;
}

.json-preview {
  margin: 12px 0;
  padding: 12px;
  background: #f5f7fa;
  border-radius: 6px;
  font-size: 13px;
}

.json-tools {
  margin-top: 12px;
  display: flex;
  gap: 8px;
}

/* 原有样式保持不变 */
.custom-form {
  padding: 20px;
  background-color: #fafafa;
  border-radius: 8px;
}

.resource-type-selection {
  margin-bottom: 25px;
  padding: 20px;
  border-radius: 12px;
  box-shadow: 0 4px 15px rgba(102, 126, 234, 0.2);
}

.resource-type-selection .el-form-item__label {
  color: white !important;
  font-weight: 600;
  font-size: 16px;
}

.resource-type-selection .el-radio-group {
  /* margin-top: 10px; */
}

.resource-type-selection .el-radio-button__inner {
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.3);
  color: white;
  padding: 12px 24px;
  border-radius: 8px;
  font-weight: 500;
  transition: all 0.3s ease;
}

.resource-type-selection .el-radio-button__inner:hover {
  background: rgba(255, 255, 255, 0.2);
  transform: translateY(-2px);
}

.resource-type-selection .el-radio-button.is-active .el-radio-button__inner {
  background: white;
  color: #667eea;
  border-color: white;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.resource-content {
  background: white;
  border-radius: 12px;
  padding: 25px;
  box-shadow: 0 2px 20px rgba(0, 0, 0, 0.08);
  border: 1px solid #e8ecf0;
}

.api-content .table-section {
  margin: 25px 0;
  background: #f8fafc;
  border-radius: 8px;
  padding: 20px;
  border: 1px solid #e2e8f0;
}

.table-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15px;
  padding-bottom: 10px;
  border-bottom: 2px solid #e2e8f0;
}

.table-header h4 {
  margin: 0;
  color: #2d3748;
  font-size: 16px;
  font-weight: 600;
}

.param-table {
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.param-table .el-table__header {
  background: #f7fafc;
}

.param-table .el-table__header th {
  background: #edf2f7;
  color: #4a5568;
  font-weight: 600;
  border: none;
}

.file-content .upload-demo {
  /* margin: 15px 0; */
}

.file-content .el-upload-dragger {
  background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
  border: 2px dashed rgba(255, 255, 255, 0.5);
  border-radius: 12px;
  padding: 40px;
  transition: all 0.3s ease;
}

.file-content .el-upload-dragger:hover {
  border-color: white;
  transform: scale(1.02);
}

.file-content .el-upload-dragger .el-icon-upload {
  font-size: 48px;
  color: white;
  margin-bottom: 15px;
}

.file-content .el-upload__tip {
  color: rgba(0, 0, 0, 0.8);
  margin-top: 10px;
}

.database-content {
  border-radius: 12px;
  padding: 25px;
  margin: -25px;
  margin-top: 0;
}

.database-content .el-form-item__label {
  color: #2d3748;
  font-weight: 600;
}

.database-content .el-input__inner {
  border-radius: 8px;
  border: 2px solid #e2e8f0;
  transition: all 0.3s ease;
}

.database-content .el-input__inner:focus {
  border-color: #667eea;
  box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}

.connection-status {
  margin-left: 15px;
  padding: 5px 12px;
  border-radius: 20px;
  font-size: 14px;
  font-weight: 500;
}

.connection-status.success {
  background: #d4edda;
  color: #155724;
  border: 1px solid #c3e6cb;
}

.connection-status.error {
  background: #f8d7da;
  color: #721c24;
  border: 1px solid #f5c6cb;
}

.connection-status.connecting {
  background: #d1ecf1;
  color: #0c5460;
  border: 1px solid #bee5eb;
}

.el-form-item {
  margin-bottom: 20px !important;
}

.el-dialog {
  border-radius: 16px;
  overflow: hidden;
}

.el-dialog__header {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  padding: 20px 30px;
}

.el-dialog__title {
  color: white;
  font-size: 18px;
  font-weight: 600;
}

.el-dialog__headerbtn .el-dialog__close {
  color: white;
  font-size: 20px;
}

.el-dialog__body {
  padding: 0;
}

.dialog-footer {
  padding: 20px 30px;
  background: #f8fafc;
  border-top: 1px solid #e2e8f0;
  text-align: right;
}

.dialog-footer .el-button {
  margin-left: 10px;
  padding: 10px 24px;
  border-radius: 8px;
  font-weight: 500;
  transition: all 0.3s ease;
}

.dialog-footer .el-button--primary {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border: none;
  box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
}

.dialog-footer .el-button--primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
}

.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  margin-bottom: 25px;
}

.el-button--mini {
  border-radius: 6px;
  font-weight: 500;
}

.el-button--success {
  background: linear-gradient(135deg, #56ab2f 0%, #a8e6cf 100%);
  border: none;
  box-shadow: 0 4px 15px rgba(86, 171, 47, 0.3);
}

.el-button--danger {
  background: linear-gradient(135deg, #ff6b6b 0%, #ffa8a8 100%);
  border: none;
}

@media (max-width: 768px) {
  .form-grid {
    grid-template-columns: 1fr;
  }

  .table-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }
}

.api-select-dialog .el-dialog__header {
  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}

.api-search-section {
  margin-bottom: 20px;
}

.api-select-table {
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}

.api-select-table .el-table__header {
  background: #f8fafc;
}

.api-select-table .el-table__header th {
  background: #edf2f7;
  color: #4a5568;
  font-weight: 600;
  border: none;
}

.api-select-table .current-row td {
  background-color: #e6f7ff !important;
  color: #1890ff;
}

.api-name {
  font-weight: 500;
  color: #2d3748;
  cursor: pointer;
}

.api-name:hover {
  color: #4facfe;
}

.pagination-wrapper {
  margin-top: 20px;
  display: flex;
  justify-content: center;
  padding: 15px 0;
  background: #f8fafc;
  border-radius: 8px;
}

.pagination-wrapper .el-pagination {
  text-align: center;
}

.api-select-dialog .dialog-footer .el-button--primary {
  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
  border: none;
  box-shadow: 0 4px 15px rgba(79, 172, 254, 0.4);
}

.api-select-dialog .dialog-footer .el-button--primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(79, 172, 254, 0.6);
}

.api-select-dialog .dialog-footer .el-button--primary:disabled {
  background: #c0c4cc;
  transform: none;
  box-shadow: none;
}

.file-preview-container {
  margin-top: 10px;
  padding: 15px;
  border: 1px solid #e2e8f0;
  border-radius: 8px;
  background: #f8fafc;
}

.image-preview {
  text-align: center;
  padding: 10px;
}

.image-preview img {
  border: 1px solid #e2e8f0;
  transition: transform 0.3s ease;
}

.image-preview img:hover {
  transform: scale(1.05);
}

.text-preview .el-card {
  border: none;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.text-preview pre {
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
  background: #f1f3f4;
  padding: 12px;
  border-radius: 4px;
  line-height: 1.4;
}

.file-info {
  text-align: center;
}

.file-info-item {
  padding: 20px;
}

.file-info-item p {
  margin: 8px 0;
  color: #606266;
  font-size: 14px;
}

.file-info-item p strong {
  color: #2d3748;
  margin-right: 8px;
}

/* 预览功能样式 */
.preview-btn {
  color: #4facfe !important;
  margin-left: 5px;
}

.preview-btn:hover {
  color: #00f2fe !important;
  text-decoration: underline;
}

.preview-dialog .el-dialog__header {
  background: linear-gradient(135deg, #43cea2 0%, #185a9d 100%);
}

.preview-content {
  padding: 20px;
  max-height: 600px;
  overflow-y: auto;
}

.preview-section {
  margin-bottom: 30px;
}

.preview-section:last-child {
  margin-bottom: 0;
}

.preview-section-title {
  font-size: 18px;
  color: #185a9d;
  margin-bottom: 15px;
  padding-bottom: 8px;
  border-bottom: 2px solid #e6f7ff;
  display: flex;
  align-items: center;
}

.preview-section-title:before {
  content: '';
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: #185a9d;
  margin-right: 8px;
}

.preview-table-section {
  margin-top: 15px;
}

.preview-table-title {
  font-size: 16px;
  color: #2c3e50;
  margin-bottom: 10px;
  font-weight: 500;
}

.no-data-tip {
  text-align: center;
  padding: 20px;
  color: #909399;
  background-color: #f9f9f9;
  border-radius: 4px;
}

.file-preview {
  margin-top: 15px;
}

.el-descriptions__label {
  font-weight: 500 !important;
}

/* 验证错误提示样式优化 */
.el-form-item__error {
  font-size: 12px;
  padding-top: 4px;
}
</style>
